package v2

import (
	rpcv1 "gluenet/internal/agent/api/rpc/v1"
	metav1 "gluenet/pkg/agent/option"
	corev1 "gluenet/pkg/agent/types"
	"gluenet/pkg/agent/v2/rpc"
)

// guid == namespace

type KubevirtGetter interface {
	VirtualMachineGetter
	VirtualMachineInstanceGetter
	VirtualMachineServiceGetter
}
type VirtualMachineGetter interface {
	VirtualMachines(guid string) VirtualMachineInterface
}

type VirtualMachineInterface interface {

	// ask agent to create a virtual machine
	//
	// Example:
	// 	vm := v1.VirtualMachine{Yaml: yaml}
	//
	// 	rlt, err := cli.VirtualMachines(UserVmApp).Create(&vm, metav1.CreateOptions{})
	Create(vm *corev1.VirtualMachine, opt metav1.CreateOptions) (*corev1.KubeVirtVirtualMachineObj, error)

	// ask agent to delete a virtual machine
	//
	// Example:
	// 	err := cli.VirtualMachines(UserVmApp).Delete(`test-vm`, metav1.DeleteOptions{})
	Delete(name string, opt metav1.DeleteOptions) error

	// ask agent to get a virtual machine's detial info
	//
	// Example:
	// 	rlt, err := cli.VirtualMachines(UserVmApp).Get(`test-vm`, metav1.GetOptions{})
	Get(name string, opt metav1.GetOptions) (*corev1.KubeVirtVirtualMachineObj, error)
}

type virtualMachines struct {
	client rpc.Interface
	guid   string
}

func newVirtualMachines(c *CoreClient, guid string) *virtualMachines {
	return &virtualMachines{
		client: c.RPCClient(),
		guid:   guid,
	}
}

func (c *virtualMachines) Create(vm *corev1.VirtualMachine, opt metav1.CreateOptions) (result *corev1.KubeVirtVirtualMachineObj, err error) {
	result = &corev1.KubeVirtVirtualMachineObj{}
	err = c.client.Invoke().
		Api(rpcv1.CreateVirtualMachine).
		Guid(c.guid).
		Resource(rpcv1.VIRTUAL_MACHINE_RESOURCE).
		Spec(*vm).
		Do().
		Into(result)
	return
}

func (c *virtualMachines) Delete(name string, opt metav1.DeleteOptions) error {
	return c.client.Invoke().
		Api(rpcv1.DeleteVirtualMachine).
		Guid(c.guid).
		Resource(rpcv1.VIRTUAL_MACHINE_RESOURCE).
		Name(name).
		Do().
		Error()
}

func (c *virtualMachines) Get(name string, opt metav1.GetOptions) (result *corev1.KubeVirtVirtualMachineObj, err error) {
	result = &corev1.KubeVirtVirtualMachineObj{}
	err = c.client.Invoke().
		Api(rpcv1.GetVirtualMachine).
		Guid(c.guid).
		Resource(rpcv1.VIRTUAL_MACHINE_RESOURCE).
		Name(name).
		Do().
		Into(result)
	return
}

type VirtualMachineInstanceGetter interface {
	VirtualMachineInstances(guid string) VirtualMachineInstanceInterface
}
type VirtualMachineInstanceInterface interface {

	// ask agent to create a virtual machine instance
	//
	// Example:
	// 	vmi.VirtualMachineInstanceName = `test-vm`
	// 	vmi.Yaml = yaml
	// 	rlt, err := cli.VirtualMachineInstances(UserVmApp).Create(&vmi, metav1.CreateOptions{})
	Create(vmi *corev1.VirtualMachineInstance, opt metav1.CreateOptions) (*corev1.KubeVirtVirtualMachineInstanceObj, error)

	// ask agent to delete a virtual machine instance
	//
	// Example:
	// 	err := cli.VirtualMachineInstances(UserVmApp).Delete(`test-vmi`, metav1.DeleteOptions{})
	Delete(name string, opt metav1.DeleteOptions) error

	// ask agent to get a virtual machine instance's detial info
	//
	// Example:
	// 	rlt, err := cli.VirtualMachineInstances(UserVmApp).Get(`test-vmi`, metav1.GetOptions{})
	Get(name string, opt metav1.GetOptions) (*corev1.KubeVirtVirtualMachineInstanceObj, error)
}

type virtualMachineInstances struct {
	client rpc.Interface
	guid   string
}

func newVirtualMachineInstances(c *CoreClient, guid string) *virtualMachineInstances {
	return &virtualMachineInstances{
		client: c.RPCClient(),
		guid:   guid,
	}
}

func (c *virtualMachineInstances) Create(vmi *corev1.VirtualMachineInstance, opt metav1.CreateOptions) (result *corev1.KubeVirtVirtualMachineInstanceObj, err error) {
	result = &corev1.KubeVirtVirtualMachineInstanceObj{}
	err = c.client.Invoke().
		Api(rpcv1.CreateVirtualMachineInstance).
		Guid(c.guid).
		Resource(rpcv1.VIRTUAL_MACHINE_INSTANCE_RESOURCE).
		Name(vmi.VirtualMachineInstanceName).
		Spec(vmi).
		Do().
		Into(result)
	return
}

func (c *virtualMachineInstances) Delete(name string, opt metav1.DeleteOptions) error {
	return c.client.Invoke().
		Api(rpcv1.DeleteVirtualMachineInstance).
		Guid(c.guid).
		Resource(rpcv1.VIRTUAL_MACHINE_INSTANCE_RESOURCE).
		Name(name).
		Do().
		Error()
}

func (c *virtualMachineInstances) Get(name string, opt metav1.GetOptions) (result *corev1.KubeVirtVirtualMachineInstanceObj, err error) {
	result = &corev1.KubeVirtVirtualMachineInstanceObj{}
	err = c.client.Invoke().
		Api(rpcv1.GetVirtualMachineInstance).
		Guid(c.guid).
		Resource(rpcv1.VIRTUAL_MACHINE_INSTANCE_RESOURCE).
		Name(name).
		Do().
		Into(result)
	return
}

type VirtualMachineServiceGetter interface {
	VirtualMachineServices(guid string) VirtualMachineServiceInterface
}

type VirtualMachineServiceInterface interface {
	// ask agent to export a virtual machine service
	//
	// Example:
	// 	vms := v1.VirtualMachineService{
	// 		VirtualMachineInstanceName: `test-vm`,
	// 		Port:                       20110,
	// 		TargetPort:                 22,
	// 		Name:                       `ssh`,
	// 		Type:                       `ClusterIP`,
	// 	}
	// 	rlt, err := cli.VirtualMachineServices(UserVmApp).Create(&vms, metav1.CreateOptions{})
	Create(vms *corev1.VirtualMachineService, opt metav1.CreateOptions) (*corev1.KubeVirtVirtualMachineServiceObj, error)

	// ask agent to delete a virtual machine service
	//
	// Example:
	// 	rlt, err := cli.VirtualMachineServices(UserVmApp).Get(`ssh`, metav1.GetOptions{})
	Delete(name string, opt metav1.DeleteOptions) error

	// ask agent to get a virtual machine service's detial info
	//
	// Example:
	// 	rlt, err := cli.VirtualMachineServices(UserVmApp).Get(`ssh`, metav1.GetOptions{})
	Get(name string, opt metav1.GetOptions) (*corev1.KubeVirtVirtualMachineServiceObj, error)
}

type VirtualMachineServices struct {
	client rpc.Interface
	guid   string
}

func newVirtualMachineServices(c *CoreClient, guid string) *VirtualMachineServices {
	return &VirtualMachineServices{
		client: c.RPCClient(),
		guid:   guid,
	}
}

func (c *VirtualMachineServices) Create(vms *corev1.VirtualMachineService, opt metav1.CreateOptions) (result *corev1.KubeVirtVirtualMachineServiceObj, err error) {
	result = &corev1.KubeVirtVirtualMachineServiceObj{}
	err = c.client.Invoke().
		Api(rpcv1.CreateVirtualMachineService).
		Guid(c.guid).
		Resource(rpcv1.VIRTUAL_MACHINE_SERVICE_RESOURCE).
		Name(vms.Name).
		Spec(vms).
		Do().
		Into(result)
	return
}

func (c *VirtualMachineServices) Delete(name string, opt metav1.DeleteOptions) error {
	return c.client.Invoke().
		Api(rpcv1.DeleteVirtualMachineService).
		Guid(c.guid).
		Resource(rpcv1.VIRTUAL_MACHINE_SERVICE_RESOURCE).
		Name(name).
		Do().
		Error()
}

func (c *VirtualMachineServices) Get(name string, opt metav1.GetOptions) (result *corev1.KubeVirtVirtualMachineServiceObj, err error) {
	result = &corev1.KubeVirtVirtualMachineServiceObj{}
	err = c.client.Invoke().
		Api(rpcv1.GetVirtualMachineService).
		Guid(c.guid).
		Resource(rpcv1.VIRTUAL_MACHINE_SERVICE_RESOURCE).
		Name(name).
		Do().
		Into(result)
	return
}
